using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SourceSystemManager
{
    public delegate void TabResponding(int docIndex, TabStatus status);
    public class TabViewManager
    {
        #region Variables
        // list label repesent for each header document
        private List<TabView> tabList = new List<TabView>();

        private List<int> closedList = new List<int>();

        private Control parent = null;

        private int maxTab;

        private TabView activeTab = null;

        private string defaultName = "New Data";

        private Point position = Point.Empty;

        private int closeAt = 0;

        private Timer timer;

        private LinkedList<int> stackList = new LinkedList<int>();
        /// <summary>
        /// delegate for post responding
        /// </summary>
        public TabResponding OnTapResponding;

        #endregion

        #region Properties

        public bool NameChanged
        {
            set
            {
                switch (activeTab.Status)
                {
                    case TabStatus.stNEW_DOCUMENT:
                        activeTab.Header.Text = this.defaultName + " *";
                        break;
                    case TabStatus.stNEW_DOCUMENT_SAVED:
                        if (activeTab.NameChanged)
                            activeTab.Header.Text = activeTab.DisplayName + " *";
                        else
                            activeTab.Header.Text = activeTab.FullName + " *";
                        break;
                    case TabStatus.stOPEN_DOCUMENT:
                        break;
                    case TabStatus.stOPEN_DOCUMENT_MODIFIED:
                        break;
                    case TabStatus.stOPEN_DOCUMENT_SAVED:
                        break;
                    case TabStatus.NONE:
                        break;
                    default:
                        break;
                }
            }
        }

        public Point Position
        {
            get { return position; }
            set { position = value; }
        }

        public string DefaultName
        {
            get { return defaultName; }
        }

        public TabView ActiveTab
        {
            get { return activeTab; }
            set { activeTab = value; }
        }

        public int MaxLengthHeader { get; set; }

        public int MaxTab
        {
            get { return maxTab; }
        }

        #endregion

        public TabViewManager(Control parent, Point pos)
        {
            this.parent = parent;
            this.position = pos;
            MaxLengthHeader = 100;
            maxTab = this.parent.Width / 100;

            timer = new Timer();
            timer.Interval = 50;
            timer.Tick += timer_Tick;
        }

        #region Methods
        void timer_Tick(object sender, EventArgs e)
        {
            for (int i = closeAt; i < tabList.Count; i++)
            {
                tabList[i].Header.Location = new Point(tabList[i].Header.Location.X - 102, tabList[i].Header.Location.Y);
            }

            timer.Stop();
            int next = GetLastView();
            if (next != -1)
                SetActive(tabList[next].Header);
        }

        /// <summary>
        /// Count number of tab
        /// </summary>
        /// <returns>number of tab</returns>
        public bool Full()
        {
            return tabList.Count == MaxTab - 1;
        }

        /// <summary>
        /// Add new tab to sequence of tab
        /// </summary>
        /// <param name="lbl">title</param>
        /// <param name="txt">text input area</param>
        /// <returns>bool value. true - if add successful; false - if add failed</returns>
        public bool AddNewTab(Label lbl, TextBox txt)
        {
            if (lbl == null || txt == null)
                return false;

            if (tabList.Count != 0)
            {
                foreach (var t in tabList)
                {
                    t.Header.BackColor = Color.DarkGray;
                }

                lbl.Location = new Point(this.position.X + tabList.Count * (lbl.Size.Width + 2), this.position.Y);
                txt.Location = new Point(this.position.X, this.position.Y + lbl.Size.Height);
            }
            else
            {
                lbl.Location = this.position;
                txt.Location = new Point(this.position.X, this.position.Y + lbl.Size.Height);
            }

            lbl.MouseDown += lbl_MouseDown;

            var tab = new TabView(this.parent, lbl, txt);
            tab.OnTapClosed += new TabCloseEventHandler(tab_OnTabClosed);
            tab.Add(TabStatus.stNEW_DOCUMENT);
            tab.Index = tab.ID = tabList.Count;
            tabList.Add(tab);

            activeTab = tab;

            stackList.AddLast(tab.ID);
            return true;
        }

        void lbl_MouseDown(object sender, MouseEventArgs e)
        {
            if (activeTab == sender)
                return;

            var h = (Label)sender;
            SetActive(h);

            stackList.AddLast(activeTab.ID);

        }

        private void tab_OnTabClosed(TabView sender)
        {
            if (tabList.Count > 0)
            {
                if (sender.Index != tabList.Count - 1)
                {
                    for (int i = sender.Index + 1; i < tabList.Count; i++)
                    {
                        tabList[i].Index--;
                    }
                }
                tabList.Remove(sender);
            }
            if (tabList.Count == 0)
                activeTab = null;

            closeAt = sender.Index;
            closedList.Add(sender.ID);
            // update position of all tabs
            timer.Start();
        }

        public void SetStatus(TabStatus status)
        {
            if (activeTab != null)
            {
                activeTab.Status = status;
            }
        }

        /// <summary>
        /// Set name for title
        /// </summary>
        /// <param name="name">name need to assigned</param>
        public void SetName(string name)
        {
            if (String.IsNullOrEmpty(name))
                return;
            activeTab.FullName = name;

            name = PrepareName(name);

            activeTab.DisplayName = name;
            if (tabList.Count != 0)
            {
                //tabList[activeTab.Index].Header.Text = name;
                activeTab.Header.Text = name;
            }
            activeTab.Status = TabStatus.stNEW_DOCUMENT_SAVED;
        }

        public bool Save()
        {
            return true;
        }

        /// <summary>
        /// this function check the name of file to display on title area
        /// if this name is too long, it will be cut ..
        /// </summary>
        /// <param name="defaultName">name of file (before cut)</param>
        /// <returns>final string for enough long</returns>
        private string PrepareName(string defaultName)
        {
            using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(new Bitmap(1, 1)))
            {
                for (int i = 0; i < defaultName.Length; i++)
                {
                    var l = defaultName.Substring(0, i + 1);
                    SizeF size = graphics.MeasureString(l, this.parent.Font);

                    if (size.Width >= MaxLengthHeader - 29 && i != defaultName.Length - 1)
                    {
                        activeTab.NameChanged = true;
                        return l + "...";
                    }
                }
            }

            activeTab.NameChanged =false;
            return defaultName;
        }

        public int GetLastView()
        {
            if (tabList.Count == 0)
            {
                stackList.Clear();
                closedList.Clear();
                return -1;
            }

            stackList.RemoveLast();

            while (TabIsClosed(stackList.Last.Value))
                stackList.RemoveLast();

            foreach (var t in tabList)
            {
                if (t.ID == stackList.Last.Value)
                    return t.Index;
            }

            return -1;
        }

        public bool TabIsClosed(int id)
        {
            foreach (var _id in closedList)
            {
                if (_id == id)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Set any tab to be focusing 
        /// </summary>
        /// <param name="curTab">the tab want to set focus</param>
        public void SetActive(Label curTab)
        {
            int id = 0;

            if (tabList.Count != 0)
            {
                foreach (var t in tabList)
                {
                    if (t.Header != curTab)
                    {
                        t.Header.BackColor = Color.DarkGray;
                    }
                    else
                    {
                        t.Header.BackColor = Color.Orange;
                        id = t.Index;
                    }
                }

                tabList[id].InputArea.BringToFront();
                tabList[id].InputArea.Focus();
                activeTab = tabList[id];
            }
        }

        /// <summary>
        /// this function allow user close current tap are working
        /// </summary>
        /// <returns>true - if close successful; false - if close failed</returns>
        public bool CloseCurrentTab()
        {
            if (activeTab != null)
            {
                if (activeTab.Close())
                {
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// close tap at specify location
        /// </summary>
        /// <param name="index">the index of tab want to close</param>
        /// <returns>true - if close successful; false - if close failed</returns>
        public bool CloseTapAt(int index)
        {
            if (tabList.Count != 0)
            {

            }
            return true;
        }

        #endregion
    }
}

